package com.lzy.system.fileManage.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.lzy.conf.JSONResult;
import com.lzy.system.fileManage.service.ISysFileService;
import com.lzy.system.organization.entity.SysUser;
import com.lzy.utils.CreateCodeeModel;
import com.zaxxer.hikari.HikariDataSource;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 附件管理 前端控制器
 * </p>
 *
 * @author lcc
 * @since 2023-12-28
 */
@RestController
@RequestMapping("/fileManage/sysFile")
@Api(tags = "附件管理")
@Slf4j
public class SysFileController {
    private ISysFileService iSysFileService;
    private SqlSessionTemplate sqlSessionTemplate;
    private HikariDataSource hikariDataSource;

    @Autowired
    public SysFileController(ISysFileService iSysFileService,SqlSessionTemplate sqlSessionTemplate,HikariDataSource hikariDataSource) {
        this.iSysFileService = iSysFileService;
        this.sqlSessionTemplate = sqlSessionTemplate;
        this.hikariDataSource = hikariDataSource;
    }

    @RequestMapping(value = "/createCodee", method = RequestMethod.POST)
    @ApiOperation("代码生成器")
    public void createCodee(
            HttpServletResponse response,
            @ApiParam("代码生成器") @RequestBody @Validated CreateCodeeModel createCodeeModel
    ) throws Exception{
        //获取项目路径
        String projectPath = System.getProperty("user.dir") + "/createCodee/" + DateUtil.date().getTime()+"-"+createCodeeModel.getParent()+"."+createCodeeModel.getModuleName();
        File dir = new File(projectPath);
        if (!dir.isDirectory()) {
            dir.mkdirs();
        }
        FastAutoGenerator.create(new DataSourceConfig.Builder((DataSource) hikariDataSource))
                .globalConfig(builder -> {
                    builder.author(createCodeeModel.getAuthor()) // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir(projectPath+"/src/main/java"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent(createCodeeModel.getParent()) // 设置父包名
                            .moduleName(createCodeeModel.getModuleName()) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mapper")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder
                            .addInclude(createCodeeModel.getTableName().split(","))
                            .entityBuilder()
                            .enableChainModel() //开启链式模型
                            .enableTableFieldAnnotation()       // 开启生成实体时生成字段注解
                            .enableLombok() //开启 Lombok
                            .naming(NamingStrategy.underline_to_camel)  //数据库表映射到实体的命名策略：默认是下划线转驼峰命。这里可以不设置
                            .columnNaming(NamingStrategy.no_change)    //数据库表字段映射到实体的命名策略：下划线转驼峰命。(默认是和naming一致，所以也可以不设置)
                            .idType(IdType.ASSIGN_UUID)
                            .controllerBuilder()
                            .enableHyphenStyle()    //开启驼峰连转字符
                            .enableRestStyle()  //开启生成 @RestController 控制器
                    ;
                    if (createCodeeModel.getIsDefField() == 1) {
                        //添加默认字段
                        builder
                                .entityBuilder()
                                .addIgnoreColumns("create_time", "update_time", "version", "del_flag")
                                .superClass("com.lzy.common.CommonEntity");
                    }
                })
                .templateConfig(builder -> {
                    if(createCodeeModel.getCodeType() == 2){
                        builder.controller("/templates/controller_crud.java");
                    }
                })
                .injectionConfig(builder -> {
                    if(createCodeeModel.getCodeType() == 2){
                        //扩展导出
                        List<CustomFile> arr_build = new ArrayList<>();
                        //dto 导出
                        arr_build.add(
                                new CustomFile.Builder()
                                        .fileName("AddDTO.java")
                                        .templatePath("/templates/entity_add_dto.java.ftl")
                                        .packageName("dto")
                                        .build()
                        );
                        arr_build.add(
                                new CustomFile.Builder()
                                        .fileName("UpdateDTO.java")
                                        .templatePath("/templates/entity_update_dto.java.ftl")
                                        .packageName("dto")
                                        .build()
                        );
                        //对象转换 convert
                        arr_build.add(
                                new CustomFile.Builder()
                                        .fileName("Convert.java")
                                        .templatePath("/templates/entity_convert.java.ftl")
                                        .packageName("dto.convert")
                                        .build()
                        );

                        builder.customMap(new HashMap<>() {{
                            put("dtoPackage", "dto");
                            put("dtoConvertPackage", "dto.convert");
                        }});

                        builder.customFile(arr_build);
                    }
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .execute();
        File zip = ZipUtil.zip(projectPath);

        // 下载文件
        FileInputStream fileInputStream = new FileInputStream(zip);
        response.reset();
        response.setContentType("application/octet-stream);charset=UTF-8");
        String fileName = zip.getName();
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));

        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fileInputStream.read(bytes)) != -1) {
            response.getOutputStream().write(bytes, 0, len);
        }
        fileInputStream.close();
    }

    @RequestMapping(value = "/saveFile", method = RequestMethod.POST)
    @ApiOperation("上传文件")
    public JSONResult uploadFile(SysUser user, @ApiParam("文件") @RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return JSONResult.errorMsg("必须上传文件");
        }
        return JSONResult.ok(iSysFileService.saveFile(user.getId(), file));
    }

    @RequestMapping(value = "/getFile", method = RequestMethod.GET)
    @ApiOperation("下载文件")
    public void getFile(HttpServletResponse response, @ApiParam("文件id") @RequestParam("fileId") String fileId,
                        @ApiParam("是否在线预览") @RequestParam(value = "isOnLine", defaultValue = "false") boolean isOnLine) throws Exception {
        String file = iSysFileService.getFile(fileId);
        // 下载文件
        FileInputStream fileInputStream = new FileInputStream(file);
        response.reset();
        response.setContentType("application/octet-stream);charset=UTF-8");
        String fileName = file.substring(file.lastIndexOf(File.separator));
        if (!isOnLine) {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        } else {
            response.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        }
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fileInputStream.read(bytes)) != -1) {
            response.getOutputStream().write(bytes, 0, len);
        }
        fileInputStream.close();
    }

    @RequestMapping(value = "/translate", method = RequestMethod.POST)
    @ApiOperation("翻译")
    public JSONResult translate(@ApiParam("文本") @RequestParam("text") String text) {
        String body = HttpUtil.get("https://gitee.com/search/translate?q=" + URLUtil.encode(text) + "");
        JSONObject jsonData = new JSONObject(body);
        return JSONResult.ok(jsonData.getStr("result"));
    }
}
